/*
 * @file     g_spi.c
 * @brief    This file provides all the SPI firmware functions.
 *
 * Change Logs:
 * Date            Author             Version        Notes
 * 2020-1-22       chengqixiong       V1.0.0         the first version
 */
#include "g_spi.h"

/**
 * @brief  Initializes the SPIx peripheral according to the specified
 *         parameters in the SPI_InitStruct .
 * @param  SPIx: Select the SPI peripheral.
 *         This parameter can be one of the following values:
 *         MSPI0, MSPI1
 * @param  SPI_InitStruct: pointer to a USART_InitTypeDef structure
 *         that contains the configuration information for the specified SPI
 *         peripheral.
 * @retval None
 */
void G_SPI_Init(SPI_TypeDef *SPIx, G_SPI_InitTypeDef *SPI_InitStruct)
{
    _ASSERT(IS_SPIx(SPIx));
    _ASSERT(IS_SPI_BAUDRATE_PRESCALER(SPI_InitStruct->BaudRatePrescaler));
    _ASSERT(IS_SPI_MODE(SPI_InitStruct->Mode));
    _ASSERT(IS_SPI_CPOL(SPI_InitStruct->CPOL));
    _ASSERT(IS_SPI_CPHA(SPI_InitStruct->CPHA));
    _ASSERT(IS_SPI_DCMIMODE(SPI_InitStruct->DCMIMODE));

    _ASSERT(IS_SPI_RW_Delay(SPI_InitStruct->RW_Delay));
    _ASSERT(IS_SPI_SLVBIDIR(SPI_InitStruct->Slv_Bidir_En));
    _ASSERT(IS_SPI_FIRSTBIT(SPI_InitStruct->FirstBit_Sel));
    _ASSERT(IS_SPI_WAIT_DMA(SPI_InitStruct->Wait_Dma));

    SPIx->CTRL.bit.CLK_DIV  = SPI_InitStruct->BaudRatePrescaler;
    SPIx->CTRL.bit.MODE     = SPI_InitStruct->Mode;
    SPIx->CTRL.bit.CPHA     = SPI_InitStruct->CPHA;
    SPIx->CTRL.bit.CPOL     = SPI_InitStruct->CPOL;
    SPIx->CTRL.bit.DCMI_EN = SPI_InitStruct->DCMIMODE;
    SPIx->CTRL.bit.RW_DELAY    = SPI_InitStruct->RW_Delay;

    SPIx->CTRL.bit.SCK_DIR = SPI_InitStruct->Slv_Bidir_En;
    SPIx->CTRL.bit.RX_PHASE  = SPI_InitStruct->RX_Phase_Sel;
    SPIx->CTRL.bit.FIRST_BIT = SPI_InitStruct->FirstBit_Sel;
    SPIx->CTRL.bit.WAIT_DMA  = SPI_InitStruct->Wait_Dma;

    DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)SPIx - sizeof(DMA_TypeDef));

    DMAx->CTRL.bit.RESET = SET;
    DMAx->CTRL.bit.RESET = RESET;
}

/**
 * @brief  Transmits one data via SPI DMA.
 * @param  SPIx: Select the SPI or the SPI peripheral.
 *         This parameter can be one of the following values:
 *         MSPI0, MSPI1.
 * @param  data: the data you want transmit.
 * @retval None
 */
void G_SPI_SendData(SPI_TypeDef *SPIx, uint8_t data)
{
    _ASSERT(IS_SPIx(SPIx));

    DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)SPIx - sizeof(DMA_TypeDef));

    DMAx->SRC_ADDR.reg               = (int)&data;
    DMAx->LEN_LOW.bit.TX_LEN_L = 1;
    DMAx->CTRL.bit.TX_LEN_H    = 0;

    DMAx->LEN_LOW.bit.RX_LEN_L = 0;
    DMAx->CTRL.bit.RX_LEN_H    = 0;

    DMAx->CTRL.bit.START          = 1;
    while (DMAx->STATUS.bit.DONE == 0);
}

/**
 * @brief  Receive one data via SPI DMA.
 * @param  SPIx: Select the SPI or the SPI peripheral.
 *         This parameter can be one of the following values:
 *         MSPI0, MSPI1.
 * @param  data: the data you want transmit.
 * @retval None
 */
uint8_t G_SPI_ReceiveData(SPI_TypeDef *SPIx)
{
    _ASSERT(IS_SPIx(SPIx));

    uint8_t data = 0;

    DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)SPIx - sizeof(DMA_TypeDef));
    DMAx->SRC_ADDR.reg               = (int)&data;

    DMAx->LEN_LOW.bit.TX_LEN_L = 0;
    DMAx->CTRL.bit.TX_LEN_H    = 0;
    DMAx->LEN_LOW.bit.RX_LEN_L = 1;
    DMAx->CTRL.bit.RX_LEN_H    = 0;

    DMAx->CTRL.bit.START          = 1;
    while (DMAx->STATUS.bit.DONE == 0);
    return data;
}

void G_SPI_SlaveBufConfig(SPI_TypeDef *SPIx, uint8_t *tbuf, uint32_t tlen, uint8_t *rbuf, uint32_t rlen)
{
    _ASSERT(IS_SPIx(SPIx));

    DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)SPIx - sizeof(DMA_TypeDef));

    DMAx->SRC_ADDR.reg  = (int)tbuf;
    DMAx->DEST_ADDR.reg = (int)rbuf;

    DMAx->LEN_LOW.bit.TX_LEN_L = tlen;
    DMAx->CTRL.bit.TX_LEN_H    = 0;
    DMAx->LEN_LOW.bit.RX_LEN_L = rlen;
    DMAx->CTRL.bit.RX_LEN_H    = 0;

    DMAx->CTRL.bit.START = 1;
}

/**
 * @brief  Transmits datas via SPI DMA.
 * @param  SPIx: Select the SPIx or the SPIx peripheral.
 *         This parameter can be one of the following values:
 *         MSPI0, MSPI1.
 * @param  buf: pointer to a buf that contains the data you want send.
 * @param  len: the buf length
 * @retval None
 */
void G_SPI_SendBuff(SPI_TypeDef *SPIx, const uint8_t *buff, uint32_t len)
{
    _ASSERT(IS_SPIx(SPIx));
    _ASSERT(NULL != buff);
    _ASSERT(len < 0xfffff);

    DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)SPIx - sizeof(DMA_TypeDef));

	/*GKT modify*/
    DMAx->SRC_ADDR.reg = (uint32_t)buff;

    DMAx->LEN_LOW.bit.TX_LEN_L = len & 0xffff;
    DMAx->CTRL.bit.TX_LEN_H    = len >> 16;
    DMAx->LEN_LOW.bit.RX_LEN_L = 0;
    DMAx->CTRL.bit.RX_LEN_H    = 0;

    DMAx->CTRL.bit.START = 1;
    while (DMAx->STATUS.bit.DONE == 0);
}
/**
 * @brief  Receive datas via SPI DMA.
 * @param  SPIx: Select the SPIx or the SPIx peripheral.
 *         This parameter can be one of the following values:
 *         MSPI0, MSPI1.
 * @param  buf: pointer to a buf that contains the data you want send.
 * @param  len: the buf length
 * @retval None
 */
void G_SPI_ReceiveBuff(SPI_TypeDef *SPIx, uint8_t *buff, uint32_t len)
{
    _ASSERT(IS_SPIx(SPIx));
    _ASSERT(NULL != buff);
    _ASSERT(len < 0xfffff);

    DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)SPIx - sizeof(DMA_TypeDef));

    DMAx->DEST_ADDR.reg              = (uint32_t)buff;

    DMAx->LEN_LOW.bit.TX_LEN_L = 0;
    DMAx->CTRL.bit.TX_LEN_H    = 0;
    DMAx->LEN_LOW.bit.RX_LEN_L = len & 0xffff;
    DMAx->CTRL.bit.RX_LEN_H    = len >> 16;

    DMAx->CTRL.bit.START          = 1;
    while (DMAx->STATUS.bit.DONE == 0);
}

/**
 * @brief  Send data first then recerive data.
 * @param  SPIx: Select the SPI or the SPI peripheral.
 *         This parameter can be one of the following values:
 *         MSPI0, MSPI1.
 * @param: TxBuff: pointer to a TxBuff  that contains the data you want send.
 * @param: TxLen: the length of send datas
 * @param: RxBuff: pointer to a TxBuff  that contains the data you want receive.
 * @param: RxLen: the length of receive datas
 * @retval None
 */
void G_SPI_SendAndReceiveData(SPI_TypeDef *SPIx, const uint8_t *TxBuff, uint32_t TxLen, uint8_t *RxBuff, uint32_t RxLen)
{
    _ASSERT(RxLen < 0xfffff);
    _ASSERT(TxLen < 0xfffff);
    DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)SPIx - sizeof(DMA_TypeDef));

    DMAx->SRC_ADDR.reg = (int)TxBuff;
    DMAx->DEST_ADDR.reg = (int)RxBuff;
    DMAx->LEN_LOW.bit.TX_LEN_L = TxLen & 0xffff;
    DMAx->CTRL.bit.TX_LEN_H    = TxLen >> 16;
    DMAx->LEN_LOW.bit.RX_LEN_L = RxLen & 0xffff;
    DMAx->CTRL.bit.RX_LEN_H    = RxLen >> 16;
    DMAx->CTRL.bit.START          = 1;
    while(DMAx->STATUS.bit.DONE == 0);
}

/**
 * @brief Enable or Disable the specified SPIx reset.
 * @param SPIx: where SPIx is the selected SPI from the SPI peripherals.
 * @param NewState: This parameter can be ENABLE or DISABLE.
 * @retval None
 */
void G_SPI_RESET(SPI_TypeDef *SPIx,G_FunctionalState NewState)
{

    if (DISABLE != NewState)
    {
        SPIx->CTRL.bit.RESET |= SPI_RESET_ON;
    }
    else
    {
        SPIx->CTRL.bit.RESET &= ~SPI_RESET_ON;
    }
}

/**
 * @brief Enable or Disable the specified SPIx DCMImode.
 * @param SPIx: where SPIx is the selected SPI from the SPI peripherals.
 * @param NewState: This parameter can be ENABLE or DISABLE.
 * @retval None
 */
void G_SPI_DCMImode(SPI_TypeDef *SPIx, G_FunctionalState NewState)
{
    if (DISABLE != NewState)
    {
        SPIx->CTRL.bit.DCMI_EN = SPI_DCMIMODE_16;
    }
    else
    {
        SPIx->CTRL.bit.DCMI_EN = SPI_DCMIMODE_8;
    }
}

/**
 * @brief Enable or Disable the specified SPIx waitdma.
 * @param SPIx: where SPIx is the selected SPI from the SPI peripherals.
 * @param NewState: This parameter can be ENABLE or DISABLE.
 * @retval None
 */
void SPI_WaitDma(SPI_TypeDef *SPIx, G_FunctionalState NewState)
{
    if (DISABLE != NewState)
    {
        SPIx->CTRL.bit.WAIT_DMA = SPI_WAIT_DMA_ENABLE;
    }
    else
    {
        SPIx->CTRL.bit.WAIT_DMA = SPI_WAIT_DMA_DISABLE;
    }
}

/**
 * @brief Enable or Disable the specified SPIx DMA interrupt.
 * @param SPIx: where SPIx is the selected SPI from the SPI peripherals.
 * @param NewState: This parameter can be ENABLE or DISABLE.
 * @retval None
 */
void G_SPI_ITConfig(SPI_TypeDef *SPIx, G_FunctionalState NewState)
{
    DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)SPIx - sizeof(DMA_TypeDef));
    if (DISABLE != NewState)
    {
        DMAx->CTRL.bit.INT_MODE = ENABLE;
    }
    else
    {
        DMAx->CTRL.bit.INT_MODE = DISABLE;
    }
}

/**
 * @brief Clear the specified SPIx DMA flag.
 * @param SPIx: where SPIx is the selected SPI from the SPI peripherals.
 * @retval None
 */
void G_SPI_ClearITPendingBit(SPI_TypeDef *SPIx)
{
    DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)SPIx - sizeof(DMA_TypeDef));
    DMAx->CTRL.bit.CLEAR_INT = 1;
}

/************************ (C) COPYRIGHT GKT *****END OF FILE****/
